/*
 * @(#)MailScheduleManager.java
 *
 * Copyright (c) 2003 DCIVision Ltd
 * All rights reserved.
 *
 * This software is the confidential and proprietary information of DCIVision
 * Ltd ("Confidential Information").  You shall not disclose such Confidential
 * Information and shall use it only in accordance with the terms of the license
 * agreement you entered into with DCIVision Ltd.
 */
package com.dcivision.workflow.core;

import java.lang.reflect.InvocationTargetException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.quartz.Job;
import org.quartz.JobExecutionException;

import com.dcivision.alert.bean.MtmUpdateAlertRecipient;
import com.dcivision.alert.bean.UpdateAlert;
import com.dcivision.alert.bean.UpdateAlertType;
import com.dcivision.alert.core.AlertManager;
import com.dcivision.framework.ApplicationException;
import com.dcivision.framework.DataSourceFactory;
import com.dcivision.framework.ErrorConstant;
import com.dcivision.framework.EventLogger;
import com.dcivision.framework.GlobalConstant;
import com.dcivision.framework.SessionContainer;
import com.dcivision.framework.SystemFunctionConstant;
import com.dcivision.framework.SystemParameterConstant;
import com.dcivision.framework.SystemParameterFactory;
import com.dcivision.framework.UserInfoFactory;
import com.dcivision.framework.Utility;
import com.dcivision.staff.bean.StaffRecord;
import com.dcivision.staff.dao.StaffRecordDAObject;
import com.dcivision.user.bean.MtmUserGroupUserRole;
import com.dcivision.user.bean.MtmUserRecordUserGroup;
import com.dcivision.user.bean.MtmUserRecordUserRole;
import com.dcivision.user.bean.UserRecord;
import com.dcivision.user.dao.MtmUserGroupUserRoleDAObject;
import com.dcivision.user.dao.MtmUserRecordUserGroupDAObject;
import com.dcivision.user.dao.MtmUserRecordUserRoleDAObject;
import com.dcivision.user.dao.UserRecordDAObject;
import com.dcivision.workflow.WorkflowErrorConstant;
import com.dcivision.workflow.bean.MtmWfProgressWfProgress;
import com.dcivision.workflow.bean.MtmWfStepNotificationRule;
import com.dcivision.workflow.bean.MtmWfStepNotificationTarget;
import com.dcivision.workflow.bean.MtmWorkflowProgressNotifyRule;
import com.dcivision.workflow.bean.MtmWorkflowProgressNotifyTarget;
import com.dcivision.workflow.bean.MtmWorkflowProgressPriorityRule;
import com.dcivision.workflow.bean.MtmWorkflowProgressUserRecord;
import com.dcivision.workflow.bean.MtmWorkflowStepUserActor;
import com.dcivision.workflow.bean.WorkflowProgress;
import com.dcivision.workflow.bean.WorkflowStep;
import com.dcivision.workflow.dao.MtmWfProgressWfProgressDAObject;
import com.dcivision.workflow.dao.MtmWfStepNotificationTargetDAObject;
import com.dcivision.workflow.dao.MtmWorkflowProgressNotifyTargetDAObject;
import com.dcivision.workflow.dao.MtmWorkflowProgressUserRecordDAObject;
import com.dcivision.workflow.dao.MtmWorkflowStepUserActorDAObject;
import com.dcivision.workflow.dao.WorkflowProgressDAObject;
import com.dcivision.workflow.dao.WorkflowStepDAObject;
/**
 * MailScheduleManager.java
 * 
 * This class is responsible for handling workflow task notifications. This
 * class is not supposed to be initialized and used by your own code as it
 * relies on the scheduler.
 * 
 * @author Rollo Chan
 * @company DCIVision Limited
 * @creation date 06/10/2003
 * @version $Revision: 1.45.2.6 $
 * @see com.dcivision.workflow.core.WorkflowOperationManager#scheduleMail
 */
public class MailScheduleManager implements Job {
  
  public static final String REVISION = "$Revision: 1.45.2.6 $";
  
  protected Log log = LogFactory.getLog(this.getClass().getName());
  SessionContainer sessionContainer = null;
  Connection conn = null;
  private Hashtable hashUserEmail = null;
  private Hashtable hashUser = null;
  private AlertManager am = null;
  
  /** Creates a new instance of SchedulerTest */
  public MailScheduleManager() {
  }
  
  /**
   * Constructs a new instance of MailScheduleManager
   * by the given SessionContainer and Connection
   *
   * @param sessionContainer The SessionContainer object,
   * @param conn The Connection object
   */
  public MailScheduleManager(SessionContainer sessionContainer, Connection conn) {
    this.sessionContainer = sessionContainer;
    this.conn = conn;
  }
  /**
   * This is not supposed to be invoked by your own code.
   * 
   * @param context The JobExecutionContext object
   * @throws JobExecutionException
   */
  public void execute(org.quartz.JobExecutionContext context) throws org.quartz.JobExecutionException {
    log.info("--------------Start MailScheduler-----------" );
    
    Integer trigerEventUserID = new Integer(0);
    String serverName = "127.0.0.1";
    String functionName = SystemFunctionConstant.WORKFLOW_TASK;
    String errorMessage = "";
    
    try {
      this.sessionContainer = new SessionContainer();
      this.conn = DataSourceFactory.getConnection();
      
      /*************************************************************
       *  get Event Log Information Begin
       *************************************************************/
      if (!Utility.isEmpty(sessionContainer.getUserRecordID())) {
        trigerEventUserID = sessionContainer.getUserRecordID();
      }
      
      if (!Utility.isEmpty(sessionContainer.getUserIPAddress())) {        
        serverName = sessionContainer.getUserIPAddress();
      }      
      
      /*************************************************************
       *  get Event Log Information End
       *************************************************************/ 
      
      am = new AlertManager(sessionContainer, conn);
      WorkflowProgressDAObject workflowProgressDAO = new WorkflowProgressDAObject(sessionContainer, conn);
      log.debug("the jobDataMap Is size =:  " + context.getJobDetail().getJobDataMap().size());
      int jobDataMapLength = context.getJobDetail().getJobDataMap().size();
      WorkflowStep wstep = (WorkflowStep)context.getJobDetail().getJobDataMap().get("workflowStep");
      WorkflowProgress wprogress = (WorkflowProgress)context.getJobDetail().getJobDataMap().get("workflowProgress");
      
      /*************************************************************
       *  get the error message info
       *************************************************************/
      errorMessage =  "MailScheduleManager.java -- Track ID: " + wprogress.getTrackID() + 
                      ", Workflow Progress ID : " + wprogress.getID() +
                      ", Workflow Step ID: " + wprogress.getWorkflowStepID() +
                      "<br> ";
      
      
      
      String processType = (String)context.getJobDetail().getJobDataMap().get("processType");
      log.info("--------------MailScheduler:" + context.getJobDetail().getFullName() + " executed.[" + new java.util.Date() + "]");
      WorkflowProgress curProgress = null;
      try {
        curProgress = (WorkflowProgress)workflowProgressDAO.getObjectByID(wprogress.getID());
      } catch (Exception ex) {
        log.debug("DB have not The Progress!!!!");
      }
      if (curProgress instanceof WorkflowProgress) {
        wprogress = curProgress;
      }
      boolean activeFlag = (WorkflowProgress.STATUS_IN_PROGRESS.equals(wprogress.getStatus()) || WorkflowProgress.STATUS_PENDING.equals(wprogress.getStatus()) || WorkflowProgress.STATUS_POST_PROGRESS.equals(wprogress.getStatus()));
      if (Utility.isEmpty(processType)) {
        MtmWfStepNotificationRule mtmWfStepNotificationRule = (MtmWfStepNotificationRule)context.getJobDetail().getJobDataMap().get("stepNotificationRule");
        Integer actionID = (Integer)context.getJobDetail().getJobDataMap().get("actionID");
        /*************************************************************
         *  reset the error message info
         *************************************************************/
        errorMessage =  "MailScheduleManager.java -- Track ID: " + wprogress.getTrackID() + 
                        ", Workflow Progress ID : " + wprogress.getID() +
                        ", Workflow Step ID: " + wprogress.getWorkflowStepID() +
                        "<br> ";
        
        if (MtmWfStepNotificationRule.NOTIFY_TRIGGER_TYPE_ARRIVED.equals(mtmWfStepNotificationRule.getNotifyTrigger())) {
          sendNotifyByMailOrSystem(wstep, wprogress, UpdateAlert.NOTIFY_TASK_ARRIVED_ACTION, mtmWfStepNotificationRule, actionID);
        } else if (MtmWfStepNotificationRule.NOTIFY_TRIGGER_TYPE_PENDING_FOR.equals(mtmWfStepNotificationRule.getNotifyTrigger())&& activeFlag) {
          sendNotifyByMailOrSystem(wstep, wprogress, UpdateAlert.NOTIFY_TASK_PENDING_FOR, mtmWfStepNotificationRule, actionID);
        } else if ( MtmWfStepNotificationRule.NOTIFY_TRIGGER_TYPE_CHECK_OUT_BY_USER.equals(mtmWfStepNotificationRule.getNotifyTrigger()) ) {
          sendNotifyByMailOrSystem(wstep, wprogress, UpdateAlert.NOTIFY_TASK_CHECK_OUT_BY_USER,mtmWfStepNotificationRule, actionID);
        } else if ( MtmWfStepNotificationRule.NOTIFY_TRIGGER_TYPE_COMPLETED_BY_USER.equals(mtmWfStepNotificationRule.getNotifyTrigger()) ) {
          sendNotifyByMailOrSystem(wstep, wprogress, UpdateAlert.NOTIFY_TASK_COMPLETED_BY_USER, mtmWfStepNotificationRule, actionID);
        } else if (MtmWfStepNotificationRule.NOTIFY_TRIGGER_TYPE_COMPLETED.equals(mtmWfStepNotificationRule.getNotifyTrigger()) ) {
          sendNotifyByMailOrSystem(wstep, wprogress, UpdateAlert.NOTIFY_TASK_COMPLETED_ACTION, mtmWfStepNotificationRule, actionID);
        } else if (MtmWfStepNotificationRule.NOTIFY_TRIGGER_TYPE_BEFORE_DUE_DATE.equals(mtmWfStepNotificationRule.getNotifyTrigger()) && activeFlag) {
          sendNotifyByMailOrSystem(wstep, wprogress, UpdateAlert.NOTIFY_BEFORE_DUE_DATE, mtmWfStepNotificationRule, actionID);
          //        } else if (MtmWfStepNotificationRule.NOTIFY_TRIGGER_TYPE_IN_PROGRESS.equals(mtmWfStepNotificationRule.getNotifyTrigger()) && (WorkflowProgress.STATUS_IN_PROGRESS.equals(currentProgress.getStatus()) || WorkflowProgress.STATUS_POST_PROGRESS.equals(currentProgress.getStatus()))) {
          //          sendNotifyByMailOrSystem(wstep, wprogress,currentProgress, ownerOrActionTakerType, UpdateAlert.NOTIFY_TASK_IN_PROGRESSING,mtmWfStepNotificationRule, actionID);
        } else if (MtmWfStepNotificationRule.NOTIFY_TRIGGER_TYPE_OVER_DUE_DATE.equals(mtmWfStepNotificationRule.getNotifyTrigger()) && activeFlag) {
          sendNotifyByMailOrSystem(wstep, wprogress, UpdateAlert.NOTIFY_TASK_ALL_OVERDUE_ACTION, mtmWfStepNotificationRule, actionID);
        } else if (MtmWfStepNotificationRule.NOTIFY_TRIGGER_TYPE_STOPPED.equals(mtmWfStepNotificationRule.getNotifyTrigger())&& WorkflowProgress.STATUS_CANCEL.equals(wprogress.getStatus())) {
          sendNotifyByMailOrSystem(wstep, wprogress,UpdateAlert.NOTIFY_STOP_TRACK, mtmWfStepNotificationRule, actionID);
          
        } else if (MtmWfStepNotificationRule.NOTIFY_TRIGGER_TYPE_APPROVED.equals(mtmWfStepNotificationRule.getNotifyTrigger())  ) {
          sendNotifyByMailOrSystem(wstep, wprogress, UpdateAlert.NOTIFY_TASK_APPROVED, mtmWfStepNotificationRule, actionID);
        } else if (MtmWfStepNotificationRule.NOTIFY_TRIGGER_TYPE_REJECT.equals(mtmWfStepNotificationRule.getNotifyTrigger()) ) {
          sendNotifyByMailOrSystem(wstep, wprogress, UpdateAlert.NOTIFY_TASK_REJECT,mtmWfStepNotificationRule, actionID);
        } else if (MtmWfStepNotificationRule.NOTIFY_TRIGGER_TYPE_YES.equals(mtmWfStepNotificationRule.getNotifyTrigger())) {
          sendNotifyByMailOrSystem(wstep, wprogress, UpdateAlert.NOTIFY_TASK_YES, mtmWfStepNotificationRule, actionID);
        } else if (MtmWfStepNotificationRule.NOTIFY_TRIGGER_TYPE_NO.equals(mtmWfStepNotificationRule.getNotifyTrigger())) {
          sendNotifyByMailOrSystem(wstep, wprogress, UpdateAlert.NOTIFY_TASK_NO, mtmWfStepNotificationRule, actionID);
        } else if ((!Utility.isEmpty( mtmWfStepNotificationRule.getNotifyTrigger())) && (mtmWfStepNotificationRule.getNotifyTrigger().indexOf(MtmWfStepNotificationRule.NOTIFY_TRIGGER_TYPE_DECISION)==0)  ) {
          sendNotifyByMailOrSystem(wstep, wprogress, mtmWfStepNotificationRule.getNotifyTrigger(), mtmWfStepNotificationRule, actionID);
          
        } else {
          log.debug("Not suitable notification: processType="+processType+", currentProgress.getStatus()="+wprogress.getStatus() );
        }
      } else {
        if (WorkflowStep.NOTIFY_OWNER_TASK_ARRIVED_BY_MAIL.equals(processType)) {
          sendNotifyArrivalByMail(wstep, wprogress);
        } else if (WorkflowStep.NOTIFY_OWNER_TASK_ARRIVED_BY_SYSTEM.equals(processType)) {
          sendNotifyArrivalBySystem(wstep,wprogress);
        } else if (WorkflowStep.NOTIFY_ALL_TASK_COMPLETED_BY_MAIL.equals(processType)) {
          //sendNotifyCompletionByMail(wstep, wprogress);//simon_del
          sendNotifyCompletionByMail(wstep, wprogress);//simon_add
        } else if (WorkflowStep.NOTIFY_ALL_TASK_COMPLETED_BY_SYSTEM.equals(processType)) {
          //sendNotifyCompletionBySystem(wstep, wprogress);//simon_del
          sendNotifyCompletionBySystem(wstep, wprogress);//simon_add
        } else if (WorkflowStep.NOTIFY_OWNER_TASK_OVERDUE_BY_MAIL.equals(processType)  && activeFlag) {
          sendNotifyOverdueOwnerByMail(wstep, wprogress);
        } else if (WorkflowStep.NOTIFY_OWNER_TASK_OVERDUE_BY_SYSTEM.equals(processType) && activeFlag) {
          sendNotifyOverdueOwnerBySystem(wstep, wprogress);
        } else if (WorkflowStep.NOTIFY_ALL_TASK_OVERDUE_BY_MAIL.equals(processType) && activeFlag ) {
          sendNotifyOverdueAllUsersByMail(wstep, wprogress);
        } else if (WorkflowStep.NOTIFY_ALL_TASK_OVERDUE_BY_SYSTEM.equals(processType)&& activeFlag ) {
          sendNotifyOverdueAllUsersBySystem(wstep, wprogress);
        } else if (WorkflowStep.NOTIFY_ALL_TRACK_STOP.equals(processType)){
          sendNotifyStopMail(wstep, wprogress);
        }
      }
      this.conn.commit();
    } catch (ApplicationException appEx) {
      /***********************************
       *  Record the Event Log.
       ***********************************/
      EventLogger.logEventMessage(trigerEventUserID, serverName, errorMessage, appEx.getMsgCode(), WorkflowErrorConstant.LOG_AUTO_TASK_ERROR_CODE, functionName, appEx.toString() );
      
      log.error(appEx, appEx);
    } catch (Exception e) {
      /***********************************
       *  Record the Event Log.
       ***********************************/
      EventLogger.logEventMessage(trigerEventUserID, serverName, errorMessage, ErrorConstant.COMMON_FATAL_ERROR, WorkflowErrorConstant.LOG_AUTO_TASK_ERROR_CODE, functionName, e.toString() );
      
      log.error(e, e);
    } finally {
      try { this.conn.close(); } catch (Exception ignore) {} finally { this.conn = null; }
    }
    log.info("--------------End MailScheduler-----------" );
  }
  /**
   * Sends out a system alert of the specified alert type
   * @param wstep The workflow step
   * @param wprogress The workflow progress
   * @param alertActionType The alert type
   * @param userRecordList The recipient list
   * @throws ApplicationException
   * @see com.dcivision.alert.bean.UpdateAlertType
   * @see com.dcivision.user.bean.UserRecord
   */
  public void sendSystemAlert(WorkflowStep wstep, WorkflowProgress wprogress, String alertActionType, List userRecordList) throws ApplicationException {
    // system log
    log.debug("start adding alert");
    SessionContainer sessionCon = new SessionContainer();
    //    if(Utility.isEmpty(conn)){
    //      try {
    //      conn = DataSourceFactory.getConnection();
    //      } catch (Exception ex){
    //        throw new ApplicationException(ex);
    //      }
    //    }
    AlertManager alertManager = new AlertManager(sessionCon, conn);
    UserRecordDAObject userRecordDAO = new UserRecordDAObject(sessionCon, conn);
    //UserRecord userRecord = (UserRecord) userRecordDAO.getObjectByID(wprogress.getCreatorID());//simon_del
    UserRecord userRecord = (UserRecord) userRecordDAO.getObjectByID(wprogress.getUpdaterID());//simon_add
    sessionCon.setUserRecord(userRecord);
    
    log.debug("start adding alert");
    UpdateAlert updateAlert = new UpdateAlert();
    updateAlert.setMessage(null);
    updateAlert.setObjectType(GlobalConstant.OBJECT_TYPE_WORKFLOW);
    updateAlert.setObjectID(wprogress.getID());
    updateAlert.setDueDate(null);
    
    log.debug("start adding alert type");
    UpdateAlertType[] updateAlertTypes = new UpdateAlertType[1];
    UpdateAlertType updateAlertType = new UpdateAlertType();
    updateAlertType.setUpdateAlertID(updateAlert.getID());
    updateAlertType.setActionType(alertActionType);
    updateAlertType.setNotifyWay(UpdateAlert.SYSTEM_NOTIFICATION);
    updateAlertType.setMessage(updateAlert.getMessage());
    updateAlertType.setDueDate(updateAlert.getDueDate());
    updateAlertTypes[0] = updateAlertType;
    
    MtmUpdateAlertRecipient[] updateRecipient = new MtmUpdateAlertRecipient[1];
    log.debug("start adding Update alert receipent");
    updateRecipient = alertManager.getRecipient(Utility.getStringArray(userRecordList), new String[0], new String[0]);
    // List notifyUserIDList = alertManager.getDistinctUserIDListByLists(Utility.getStringArray(userRecordList), new String[0], new String[0]);
    updateAlert =alertManager.createUpdateAlert(updateAlert, updateAlertTypes, updateRecipient, null, "", null, "", sessionCon.getUserRecordID(), userRecordList);
  }
  
  private void sendSystemAlertAddedActionID(WorkflowStep wstep, WorkflowProgress wprogress, String alertActionType, Integer actionID, List userRecordList) throws ApplicationException {
    // system log
    log.debug("start adding alert");
    SessionContainer sessionCon = new SessionContainer();
    //    if(Utility.isEmpty(conn)){
    //      try {
    //      conn = DataSourceFactory.getConnection();
    //      } catch (Exception ex){
    //        throw new ApplicationException(ex);
    //      }
    //    }
    AlertManager alertManager = new AlertManager(sessionCon, conn);
    UserRecordDAObject userRecordDAO = new UserRecordDAObject(sessionCon, conn);
    UserRecord userRecord = (UserRecord) userRecordDAO.getObjectByID(wprogress.getCreatorID());
    sessionCon.setUserRecord(userRecord);
    
    log.debug("start adding alert");
    UpdateAlert updateAlert = new UpdateAlert();
    updateAlert.setMessage(null);
    updateAlert.setObjectType(GlobalConstant.OBJECT_TYPE_WORKFLOW);
    updateAlert.setObjectID(wprogress.getID());
    updateAlert.setDueDate(null);
    
    log.debug("start adding alert type");
    UpdateAlertType[] updateAlertTypes = new UpdateAlertType[1];
    UpdateAlertType updateAlertType = new UpdateAlertType();
    updateAlertType.setUpdateAlertID(updateAlert.getID());
    updateAlertType.setActionType(alertActionType);
    updateAlertType.setNotifyWay(UpdateAlert.SYSTEM_NOTIFICATION);
    updateAlertType.setMessage(updateAlert.getMessage());
    updateAlertType.setDueDate(updateAlert.getDueDate());
    updateAlertTypes[0] = updateAlertType;
    
    MtmUpdateAlertRecipient[] updateRecipient = new MtmUpdateAlertRecipient[1];
    log.debug("start adding Update alert receipent, size="+userRecordList.size());
    updateRecipient = alertManager.getRecipient(Utility.getStringArray(userRecordList), new String[0], new String[0]);
    // List notifyUserIDList = alertManager.getDistinctUserIDListByLists(Utility.getStringArray(userRecordList), new String[0], new String[0]);
    updateAlert =alertManager.createUpdateAlert(updateAlert, updateAlertTypes, updateRecipient, actionID, "", null, "", sessionCon.getUserRecordID(), userRecordList);
  }
  
  
  //* completion mail
  private void sendNotifyCompletionByMail(WorkflowStep wstep, WorkflowProgress wprogress) throws ApplicationException {
    ArrayList recipientList = this.getAllActorEmailInfoListByWorkflow(wprogress.getTrackID());
    ArrayList filteredList=getfilteredListUserIDsFromWFStep(recipientList,wstep,wprogress);
    boolean isHaveDelegationTargetID=false;
    for(int i=0;filteredList.size()>=1 && i<filteredList.size();i++){
      if((wprogress.getUpdaterID()).equals(filteredList.get(i))){
        isHaveDelegationTargetID=true;
      }
    }
    if(!isHaveDelegationTargetID){
      filteredList.add(wprogress.getUpdaterID());
    }
    //simon_add_E
    am.createWorkflowEmailNotification(wprogress.getID(), UpdateAlert.WORKFLOW_TYPE, UpdateAlert.NOTIFY_TASK_COMPLETED_ACTION, filteredList);
  }
  
  //* completion system log
  private void sendNotifyCompletionBySystem(WorkflowStep wstep, WorkflowProgress wprogress) throws ApplicationException {
    ArrayList recipientList = this.getAllActorEmailInfoListByWorkflow(wprogress.getTrackID());
    ArrayList filteredList=getfilteredListUserIDsFromWFStep(recipientList,wstep,wprogress);
    boolean isHaveDelegationTargetID=false;
    for(int i=0;filteredList.size()>=1 && i<filteredList.size();i++){
      if((wprogress.getUpdaterID()).equals(filteredList.get(i))){
        isHaveDelegationTargetID=true;
      }
    }
    if(!isHaveDelegationTargetID){
      filteredList.add(wprogress.getUpdaterID());
    }
    //simon_add_E
    sendSystemAlert(wstep, wprogress, UpdateAlert.NOTIFY_TASK_COMPLETED_ACTION, filteredList);
  }
  
  //arrival mail
  private void sendNotifyArrivalByMail(WorkflowStep wstep, WorkflowProgress wprogress) throws ApplicationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException {
    ArrayList recipientList = this.getAllActorEmailInfoListByStep(wstep, wprogress);
    ArrayList filteredList=getfilteredListUserIDsFromWFStep(recipientList,wstep,wprogress);
    am.createWorkflowEmailNotification(wprogress.getID(), UpdateAlert.WORKFLOW_TYPE, UpdateAlert.NOTIFY_TASK_ARRIVED_ACTION, filteredList);
  }
  /**
   * TODO send notify where che notification rule is user decision and Task is Arrived
   * @param wstep
   * @param wprogress
   * @param currentProgress
   * @param ownerType
   * @throws ApplicationException
   */
  private void sendNotifyByMailOrSystem(WorkflowStep wstep, WorkflowProgress wprogress,  String notifiyTaskAction, MtmWfStepNotificationRule mtmWfStepNotificationRule, Integer actionID) throws ApplicationException {
    String notifyAtMethod = mtmWfStepNotificationRule.getNotifyAckMethod();
    Integer notifyAtMat = mtmWfStepNotificationRule.getNotifyAtAmt();
    Integer notifyAtFiled = mtmWfStepNotificationRule.getNotifyAtField();
    boolean isProgressRuleBean = false;
    if (mtmWfStepNotificationRule instanceof MtmWorkflowProgressNotifyRule){
      isProgressRuleBean = true;
    }
    try {
      ArrayList recipientList = this.getAllActorEmailInfoListByWorkflowProgressAndRuleID(wprogress, mtmWfStepNotificationRule.getID(), isProgressRuleBean);
      ArrayList filteredList=getfilteredListUserIDsFromWFStep(recipientList,wstep,wprogress);
      //simon_add_S
      if ( MtmWfStepNotificationRule.NOTIFY_TRIGGER_TYPE_COMPLETED_BY_USER.equals(mtmWfStepNotificationRule.getNotifyTrigger()) ) {
        boolean isHaveDelegationTargetID=false;
        for(int i=0;filteredList.size()>=1 && i<filteredList.size();i++){
          if(actionID.equals(filteredList.get(i))){
            isHaveDelegationTargetID=true;
          }
        }
        if(!isHaveDelegationTargetID){
          filteredList.add(actionID);
        }
      }
      //simon_add_E
      if (notifyAtMethod.indexOf(MtmWorkflowProgressPriorityRule.NOTIFY_BY_EMAIL) >-1) {
        am.createWorkflowEmailNotification(wprogress.getID(), UpdateAlert.WORKFLOW_TYPE, notifiyTaskAction, filteredList, notifyAtMat, notifyAtFiled, actionID);
      }
      if (notifyAtMethod.indexOf(MtmWorkflowProgressPriorityRule.NOTIFY_BY_SYSTEM) >-1) {
        if (MtmWfStepNotificationRule.NOTIFY_TRIGGER_TYPE_CHECK_OUT_BY_USER.equals(mtmWfStepNotificationRule.getNotifyTrigger()) || MtmWfStepNotificationRule.NOTIFY_TRIGGER_TYPE_COMPLETED_BY_USER.equals(mtmWfStepNotificationRule.getNotifyTrigger())) {
          sendSystemAlertAddedActionID(wstep, wprogress, notifiyTaskAction, actionID, filteredList);
        } else {
          sendSystemAlert(wstep, wprogress, notifiyTaskAction, filteredList);
        }
      }
    } catch (ApplicationException appEx) {//simon_add
      throw appEx;//simon_add
    }catch (Exception ex) {
      log.error(ex, ex);
    }
  }
  
  /**
   * TODO send notify where the notification rule is user decision and Task is completed
   * @param wstep
   * @param wprogress
   * @param currentProgress
   * @param ownerType
   * @throws ApplicationException
   * @throws NoSuchMethodException 
   * @throws InvocationTargetException 
   * @throws IllegalAccessException 
   */
  /*
   private void sendNotifyCompletionByMail(WorkflowStep wstep, WorkflowProgress wprogress, WorkflowProgress currentProgress, String ownerType) throws ApplicationException {
   if (MtmWfStepNotificationTarget.TARGET_TYPE_ACTION_TAKER.equals(ownerType)) {
   ArrayList recipientList = this.getAllActionTakerEmailInfoListByStep(wprogress);
   am.createWorkflowEmailNotification(currentProgress.getID(), UpdateAlert.WORKFLOW_TYPE, UpdateAlert.NOTIFY_TASK_COMPLETED_ACTION, recipientList);
   } else {
   ArrayList recipientList = this.getAllActorEmailInfoListByStep(wstep, wprogress);
   am.createWorkflowEmailNotification(currentProgress.getID(), UpdateAlert.WORKFLOW_TYPE, UpdateAlert.NOTIFY_TASK_COMPLETED_ACTION, recipientList);
   }
   }
   */
  
  //arrival system log
  private void sendNotifyArrivalBySystem(WorkflowStep wstep, WorkflowProgress wprogress) throws ApplicationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException {
    ArrayList recipientList = this.getAllActorEmailInfoListByStep(wstep, wprogress);
    ArrayList filteredList=getfilteredListUserIDsFromWFStep(recipientList,wstep,wprogress);
    sendSystemAlert(wstep, wprogress, UpdateAlert.NOTIFY_TASK_ARRIVED_ACTION, filteredList);
  }
  
  /**
   * get the filtered UserIDs List From the WorkFlow Step Filter
   * @param userIdsList
   * @param wstep
   * @param wprogress
   * @return
   * @throws ApplicationException
   */
  private ArrayList getfilteredListUserIDsFromWFStep(ArrayList userIdsList, WorkflowStep wstep, WorkflowProgress wprogress) throws ApplicationException {
    WorkflowStepDAObject setpDAO = new WorkflowStepDAObject(this.sessionContainer, this.conn);
    return setpDAO.getfilteredListUserIDsFromWFStep(userIdsList, wstep, wprogress);
  }

  // overdue owner mail
  private void sendNotifyOverdueOwnerByMail(WorkflowStep wstep, WorkflowProgress wprogress) throws ApplicationException {
    if (!wprogress.getStatus().equals(WorkflowProgress.STATUS_PENDING)) {
      return;
    }
    ArrayList recipientList = this.getAllActorEmailInfoListByStep(wstep, wprogress);
    ArrayList filteredList=getfilteredListUserIDsFromWFStep(recipientList,wstep,wprogress);
    am.createWorkflowEmailNotification(wprogress.getID(), UpdateAlert.WORKFLOW_TYPE, UpdateAlert.NOTIFY_TASK_OWNER_OVERDUE_ACTION, filteredList);
  }
  
  // overdue owner system log
  private void sendNotifyOverdueOwnerBySystem(WorkflowStep wstep, WorkflowProgress wprogress) throws ApplicationException {
    if (!wprogress.getStatus().equals(WorkflowProgress.STATUS_PENDING)) {
      return;
    }
    ArrayList recipientList = this.getAllActorEmailInfoListByStep(wstep, wprogress);
    ArrayList filteredList=getfilteredListUserIDsFromWFStep(recipientList,wstep,wprogress);
    sendSystemAlert(wstep, wprogress, UpdateAlert.NOTIFY_TASK_OWNER_OVERDUE_ACTION, filteredList);
  }
  
  // overdue mail to all
  private void sendNotifyOverdueAllUsersByMail(WorkflowStep wstep, WorkflowProgress wprogress) throws ApplicationException {
    if (!wprogress.getStatus().equals(WorkflowProgress.STATUS_PENDING)) {
      return;
    }
    ArrayList recipientList = this.getAllActorEmailInfoListByWorkflow(wprogress.getTrackID());
    log.debug("*********");
    log.debug("recipientList.size is "+recipientList.size());
    log.debug("*********");
    ArrayList filteredList=getfilteredListUserIDsFromWFStep(recipientList,wstep,wprogress);
    am.createWorkflowEmailNotification(wprogress.getID(), UpdateAlert.WORKFLOW_TYPE, UpdateAlert.NOTIFY_TASK_ALL_OVERDUE_ACTION, filteredList);
  }
  
  // overdue system to all
  private void sendNotifyOverdueAllUsersBySystem(WorkflowStep wstep, WorkflowProgress wprogress) throws ApplicationException {
    if (!wprogress.getStatus().equals(WorkflowProgress.STATUS_PENDING)) {
      return;
    }
    ArrayList recipientList = this.getAllActorEmailInfoListByWorkflow(wprogress.getTrackID());
    log.debug("*********");
    log.debug("recipientList.size is "+recipientList.size());
    log.debug("*********");
    ArrayList filteredList=getfilteredListUserIDsFromWFStep(recipientList,wstep,wprogress);
    sendSystemAlert(wstep, wprogress, UpdateAlert.NOTIFY_TASK_ALL_OVERDUE_ACTION, filteredList);
  }
  
  private void sendNotifyStopMail(WorkflowStep wstep, WorkflowProgress wprogress) throws ApplicationException {
    List notificationWay = SystemParameterFactory.getSystemParameterList(SystemParameterConstant.WORKFLOW_STOP_WORKFLOW_NOTIFICATION_WAY);
    
    ArrayList recipientList = this.getAllActorEmailInfoListByWorkflow(wprogress.getTrackID());
    ArrayList filteredList=getfilteredListUserIDsFromWFStep(recipientList,wstep,wprogress);
    if (notificationWay.contains(MtmWfStepNotificationRule.NOTIFY_ACK_METHOD_TYPE_EMAIL)) {
      am.createWorkflowEmailNotification(wprogress.getID(), UpdateAlert.WORKFLOW_TYPE, UpdateAlert.NOTIFY_STOP_TRACK, filteredList);
    }
    
    // system log
    if (notificationWay.contains(MtmWfStepNotificationRule.NOTIFY_ACK_METHOD_TYPE_SYSTEM)) {
      sendSystemAlert(wstep, wprogress, UpdateAlert.NOTIFY_STOP_TRACK, filteredList);
    }
  }    
  
  private ArrayList getInvolvedActorEmailInfoListByTrack(Integer workflowTrackID) throws ApplicationException {
    Hashtable recipientHash = new Hashtable();
    ArrayList resultList = new ArrayList();
    ArrayList tmpAryList = new ArrayList();
    String sqlStat = "";
    
    SessionContainer sessionCon = new SessionContainer();
    
    MtmUserGroupUserRoleDAObject mtmUserGroupUserRoleDAO = new MtmUserGroupUserRoleDAObject(sessionCon, conn);
    MtmUserRecordUserRoleDAObject mtmUserRecordUserRoleDAO = new MtmUserRecordUserRoleDAObject(sessionCon, conn);
    MtmUserRecordUserGroupDAObject mtmUserRecordUserGroupDAO = new MtmUserRecordUserGroupDAObject(sessionCon, conn);
    
    sqlStat += "SELECT DISTINCT MWSUA.ACTOR_TYPE, MWSUA.ACTOR_ID ";
    sqlStat += "FROM   MTM_WF_STEP_USER_ACTOR MWSUA, WORKFLOW_STEP WS, WORKFLOW_PROGRESS WP ";
    sqlStat += "WHERE  MWSUA.WORKFLOW_STEP_ID = WS.ID AND ";
    sqlStat += "       MWSUA.WORKFLOW_STEP_ID = WP.WORKFLOW_STEP_ID AND ";
    sqlStat += "       WP.TRACK_ID = ? ";
    
    java.sql.PreparedStatement preStat = null;
    java.sql.ResultSet rs = null;
    try {
      preStat = this.conn.prepareStatement(sqlStat);
      preStat.setInt(1, workflowTrackID.intValue());
      rs = preStat.executeQuery();
      while (rs.next()) {
        String[] tmpAry = new String[] { rs.getString(1), rs.getString(2) };
        tmpAryList.add(tmpAry);
      }
    } catch (Exception e) {
      log.error(e, e);
    } finally {
      try { rs.close(); } catch (Exception ignore) {} finally { rs = null; }
      try { preStat.close(); } catch (Exception ignore) {} finally { preStat = null; }
    }
    
    for (int i = 0; i < tmpAryList.size(); i++) {
      String[] mtmUserActor = (String[])tmpAryList.get(i);
      if (MtmWorkflowStepUserActor.ACTOR_TYPE_USER.equals(mtmUserActor[0])) {
        // Directly Use Actor ID As User ID.
        if (recipientHash.get(new Integer(mtmUserActor[1])) == null) {
          recipientHash.put(new Integer(mtmUserActor[1]), new String[]{ UserInfoFactory.getUserFullName(new Integer(mtmUserActor[1])), UserInfoFactory.getUserEmailAddress(new Integer(mtmUserActor[1])) });
        }
      } else if (MtmWorkflowStepUserActor.ACTOR_TYPE_GROUP.equals(mtmUserActor[0])) {
        // Find User IDs By Group ID.
        ArrayList groupAry = new ArrayList();
        groupAry.add(new Integer(mtmUserActor[1]));
        ArrayList tmpAry = (ArrayList)mtmUserRecordUserGroupDAO.getListByUserGroupAry(groupAry);
        for (int j = 0; j < tmpAry.size(); j++) {
          MtmUserRecordUserGroup tmpUserRecordUserGroup = (MtmUserRecordUserGroup)tmpAry.get(j);
          if (recipientHash.get(tmpUserRecordUserGroup.getUserRecordID()) == null) {
            recipientHash.put(tmpUserRecordUserGroup.getUserRecordID(), new String[]{ UserInfoFactory.getUserFullName(tmpUserRecordUserGroup.getUserRecordID()), UserInfoFactory.getUserEmailAddress(tmpUserRecordUserGroup.getUserRecordID()) });
          }
        }
      } else if (MtmWorkflowStepUserActor.ACTOR_TYPE_ROLE.equals(mtmUserActor[0])) {
        // Find User IDs By Role ID.
        ArrayList roleAry = new ArrayList();
        roleAry.add(new Integer(mtmUserActor[1]));
        ArrayList tmpAry = (ArrayList)mtmUserRecordUserRoleDAO.getListByUserRoleAry(roleAry);
        for (int j = 0; j < tmpAry.size(); j++) {
          MtmUserRecordUserRole tmpUserRecordUserRole = (MtmUserRecordUserRole)tmpAry.get(j);
          if (recipientHash.get(tmpUserRecordUserRole.getUserRecordID()) == null) {
            recipientHash.put(tmpUserRecordUserRole.getUserRecordID(), new String[]{ UserInfoFactory.getUserFullName(tmpUserRecordUserRole.getUserRecordID()), UserInfoFactory.getUserEmailAddress(tmpUserRecordUserRole.getUserRecordID()) });
          }
        }
        
        ArrayList tmpGroupAry = (ArrayList)mtmUserGroupUserRoleDAO.getListByUserRoleAry(roleAry);
        for (int j = 0; j < tmpGroupAry.size(); j++) {
          MtmUserGroupUserRole tmpUserGroupUserRole = (MtmUserGroupUserRole)tmpGroupAry.get(j);
          
          ArrayList groupAry = new ArrayList();
          groupAry.add(tmpUserGroupUserRole.getUserGroupID());
          ArrayList tmpUserAry = (ArrayList)mtmUserRecordUserGroupDAO.getListByUserGroupAry(groupAry);
          for (int k = 0; k < tmpUserAry.size(); k++) {
            MtmUserRecordUserGroup tmpUserRecordUserGroup = (MtmUserRecordUserGroup)tmpUserAry.get(k);
            if (recipientHash.get(tmpUserRecordUserGroup.getUserRecordID()) == null) {
              recipientHash.put(tmpUserRecordUserGroup.getUserRecordID(), new String[]{ UserInfoFactory.getUserFullName(tmpUserRecordUserGroup.getUserRecordID()), UserInfoFactory.getUserEmailAddress(tmpUserRecordUserGroup.getUserRecordID()) });
            }
          }
        }
      }
    }
    
    for (Enumeration e = recipientHash.keys(); e.hasMoreElements();) {
      //String[] tmpStrAry = (String[])recipientHash.get(e.nextElement());
      resultList.add(e.nextElement());
    }
    
    return(resultList);
  }
  
  private ArrayList getAllActorEmailInfoListByWorkflow(Integer trackID) throws ApplicationException {
    Hashtable recipientHash = new Hashtable();
    ArrayList resultList = new ArrayList();
    ArrayList tmpAryList = new ArrayList();
    String sqlStat = "";
    
    SessionContainer sessionCon = new SessionContainer();
    
    MtmUserRecordUserGroupDAObject mtmUserRecordUserGroupDAO = new MtmUserRecordUserGroupDAObject(sessionCon, conn);
    MtmUserRecordUserRoleDAObject mtmUserRecordUserRoleDAO = new MtmUserRecordUserRoleDAObject(sessionCon, conn);
    MtmUserGroupUserRoleDAObject mtmUserGroupUserRoleDAO = new MtmUserGroupUserRoleDAObject(sessionCon, conn);
    
    sqlStat += "SELECT DISTINCT A.USER_RECORD_ID ";
    sqlStat += "FROM   MTM_WF_PROGRESS_USER_RECORD A, WORKFLOW_PROGRESS P ";
    sqlStat += "WHERE  P.ID = A.WORKFLOW_PROGRESS_ID AND P.TRACK_ID = ? ";
    sqlStat += "       AND A.WORKFLOW_ACTION <> ? AND A.RECORD_STATUS = ? ";
    
    PreparedStatement preStat = null;
    ResultSet rs = null;
    try {
      preStat = this.conn.prepareStatement(sqlStat);
      
      preStat.setInt(1, trackID.intValue());
      preStat.setString(2, WorkflowProgress.STATUS_PENDING);
      preStat.setString(3, GlobalConstant.RECORD_STATUS_ACTIVE);
      rs = preStat.executeQuery();
      while (rs.next()) {
        String[] tmpAry = new String[] { rs.getString(1) };
        tmpAryList.add(tmpAry);
      }
    } catch (Exception e) {
      log.error(e, e);
    } finally {
      try { rs.close(); } catch (Exception ignore) {} finally { rs = null; }
      try { preStat.close(); } catch (Exception ignore) {} finally { preStat = null; }
    }
    
    for (int i = 0; i < tmpAryList.size(); i++) {
      String[] mtmUserActor = (String[])tmpAryList.get(i);
      //      if (MtmWorkflowStepUserActor.ACTOR_TYPE_USER.equals(mtmUserActor[0])) {
      // Directly Use Actor ID As User ID.
      if (recipientHash.get(new Integer(mtmUserActor[0])) == null) {
        recipientHash.put(new Integer(mtmUserActor[0]), new String[]{ UserInfoFactory.getUserFullName(new Integer(mtmUserActor[0])), UserInfoFactory.getUserEmailAddress(new Integer(mtmUserActor[0])) });
      }
      /*     } else if (MtmWorkflowStepUserActor.ACTOR_TYPE_GROUP.equals(mtmUserActor[0])) {
       // Find User IDs By Group ID.
        ArrayList groupAry = new ArrayList();
        groupAry.add(new Integer(mtmUserActor[1]));
        ArrayList tmpAry = (ArrayList)mtmUserRecordUserGroupDAO.getListByUserGroupAry(groupAry);
        for (int j = 0; j < tmpAry.size(); j++) {
        MtmUserRecordUserGroup tmpUserRecordUserGroup = (MtmUserRecordUserGroup)tmpAry.get(j);
        if (recipientHash.get(tmpUserRecordUserGroup.getUserRecordID()) == null) {
        recipientHash.put(tmpUserRecordUserGroup.getUserRecordID(), new String[]{ UserInfoFactory.getUserFullName(tmpUserRecordUserGroup.getUserRecordID()), UserInfoFactory.getUserEmailAddress(tmpUserRecordUserGroup.getUserRecordID()) });
        }
        }
        } else if (MtmWorkflowStepUserActor.ACTOR_TYPE_ROLE.equals(mtmUserActor[0])) {
        // Find User IDs By Role ID.
         ArrayList roleAry = new ArrayList();
         roleAry.add(new Integer(mtmUserActor[1]));
         ArrayList tmpAry = (ArrayList)mtmUserRecordUserRoleDAO.getListByUserRoleAry(roleAry);
         for (int j = 0; j < tmpAry.size(); j++) {
         MtmUserRecordUserRole tmpUserRecordUserRole = (MtmUserRecordUserRole)tmpAry.get(j);
         if (recipientHash.get(tmpUserRecordUserRole.getUserRecordID()) == null) {
         recipientHash.put(tmpUserRecordUserRole.getUserRecordID(), new String[]{ UserInfoFactory.getUserFullName(tmpUserRecordUserRole.getUserRecordID()), UserInfoFactory.getUserEmailAddress(tmpUserRecordUserRole.getUserRecordID()) });
         }
         }
         ArrayList tmpGroupAry = (ArrayList)mtmUserGroupUserRoleDAO.getListByUserRoleAry(roleAry);
         for (int j = 0; j < tmpGroupAry.size(); j++) {
         MtmUserGroupUserRole tmpUserGroupUserRole = (MtmUserGroupUserRole)tmpGroupAry.get(j);
         
         ArrayList groupAry = new ArrayList();
         groupAry.add(tmpUserGroupUserRole.getUserGroupID());
         ArrayList tmpUserAry = (ArrayList)mtmUserRecordUserGroupDAO.getListByUserGroupAry(groupAry);
         for (int k = 0; k < tmpUserAry.size(); k++) {
         MtmUserRecordUserGroup tmpUserRecordUserGroup = (MtmUserRecordUserGroup)tmpUserAry.get(k);
         if (recipientHash.get(tmpUserRecordUserGroup.getUserRecordID()) == null) {
         recipientHash.put(tmpUserRecordUserGroup.getUserRecordID(), new String[]{ UserInfoFactory.getUserFullName(tmpUserRecordUserGroup.getUserRecordID()), UserInfoFactory.getUserEmailAddress(tmpUserRecordUserGroup.getUserRecordID()) });
         }
         }
         }
         }*/
    }
    
    for (Enumeration e = recipientHash.keys(); e.hasMoreElements();) {
      //String[] tmpStrAry = (String[])recipientHash.get(e.nextElement());
      resultList.add(e.nextElement());
    }
    
    return(resultList);
  }
  /**
   * Gets all the recipients id who is the owner of the given workflow progress/step
   * @param wstep The workflow step
   * @param wprogress The workflow progress
   * @return List of user record id
   * @throws ApplicationException
   * @see com.dcivision.user.bean.UserRecord
   */
  public ArrayList getAllActorEmailInfoListByStep(WorkflowStep wstep, WorkflowProgress wprogress) throws ApplicationException {
    Hashtable recipientHash = new Hashtable();
    ArrayList resultList = new ArrayList();
    
    SessionContainer sessionCon = new SessionContainer();
    
    MtmWorkflowStepUserActorDAObject mtmWfStepUserActorDAO = new MtmWorkflowStepUserActorDAObject(sessionCon, conn);
    MtmUserRecordUserGroupDAObject mtmUserRecordUserGroupDAO = new MtmUserRecordUserGroupDAObject(sessionCon, conn);
    MtmUserRecordUserRoleDAObject mtmUserRecordUserRoleDAO = new MtmUserRecordUserRoleDAObject(sessionCon, conn);
    MtmUserGroupUserRoleDAObject mtmUserGroupUserRoleDAO = new MtmUserGroupUserRoleDAObject(sessionCon, conn);
    WorkflowProgressDAObject progressDAO = new WorkflowProgressDAObject(sessionCon, conn);
    WorkflowStepDAObject stepDAO = new WorkflowStepDAObject(sessionCon, conn);
    UserRecordDAObject userDAO = new UserRecordDAObject(sessionCon, conn);
    StaffRecordDAObject staffDAO = new StaffRecordDAObject(sessionCon, conn);
    MtmWfProgressWfProgressDAObject wfProgressTwoDAO = new MtmWfProgressWfProgressDAObject(sessionCon, conn);
    MtmWorkflowProgressUserRecordDAObject mtmWfProgressUserRecordDAO = new MtmWorkflowProgressUserRecordDAObject(sessionCon, conn);
    ArrayList userActorAry = (ArrayList)mtmWfStepUserActorDAO.getListByWorkflowStepID(wstep.getID());
    boolean isDynamic=false;
//sliever.hu.add
    for (int I = 0; I < userActorAry.size(); I++) {
	      MtmWorkflowStepUserActor mtmUserActor1= (MtmWorkflowStepUserActor)userActorAry.get(I);
	      if (MtmWorkflowStepUserActor.ACTOR_TYPE_RUNTIME_ASSIGN.equals(mtmUserActor1.getActorType())) {
	        	  isDynamic=true;
	      }
	 }
    if(isDynamic){
    	 for (int ii = 0; ii < userActorAry.size(); ii++) {
    	      MtmWorkflowStepUserActor mtmUserActor2= (MtmWorkflowStepUserActor)userActorAry.get(ii);
    	      if (MtmWorkflowStepUserActor.ACTOR_TYPE_RUNTIME_ASSIGN.equals(mtmUserActor2.getActorType())) {
    	          List userList2 = progressDAO.getListUserIDForDynamicAssignProgress(wprogress.getID());
    	          for (int jj=0; jj<userList2.size(); jj++) {
    	            Integer userID = (Integer) userList2.get(jj);
    	            recipientHash.put(userID, new String[]{UserInfoFactory.getUserFullName(userID), UserInfoFactory.getUserEmailAddress(userID)} );
    	          }
    	      }
    	 }
    }
//sliever.hu.add
 else{
    for (int i = 0; i < userActorAry.size(); i++) {
      MtmWorkflowStepUserActor mtmUserActor = (MtmWorkflowStepUserActor)userActorAry.get(i);
      if (MtmWorkflowStepUserActor.ACTOR_TYPE_RUNTIME_ASSIGN.equals(mtmUserActor.getActorType())) {
          List userList = progressDAO.getListUserIDForDynamicAssignProgress(wprogress.getID());
          for (int j=0; j<userList.size(); j++) {
            Integer userID = (Integer) userList.get(j);
            recipientHash.put(userID, new String[]{UserInfoFactory.getUserFullName(userID), UserInfoFactory.getUserEmailAddress(userID)} );
          }
      }else if (MtmWorkflowStepUserActor.ACTOR_TYPE_USER.equals(mtmUserActor.getActorType())) {
          // Directly Use Actor ID As User ID.
          if (recipientHash.get(mtmUserActor.getActorID()) == null) {
            recipientHash.put(mtmUserActor.getActorID(), new String[]{ UserInfoFactory.getUserFullName(mtmUserActor.getActorID()), UserInfoFactory.getUserEmailAddress(mtmUserActor.getActorID()) });
          }
      } else if (MtmWorkflowStepUserActor.ACTOR_TYPE_GROUP.equals(mtmUserActor.getActorType())) {
        // Find User IDs By Group ID.
        List groupAry = new ArrayList();
        groupAry.add(mtmUserActor.getActorID());
        ArrayList tmpAry = (ArrayList)mtmUserRecordUserGroupDAO.getListByUserGroupAry(groupAry);
        for (int j = 0; j < tmpAry.size(); j++) {
          MtmUserRecordUserGroup tmpUserRecordUserGroup = (MtmUserRecordUserGroup)tmpAry.get(j);
          if (recipientHash.get(tmpUserRecordUserGroup.getUserRecordID()) == null) {
            recipientHash.put(tmpUserRecordUserGroup.getUserRecordID(), new String[]{ UserInfoFactory.getUserFullName(tmpUserRecordUserGroup.getUserRecordID()), UserInfoFactory.getUserEmailAddress(tmpUserRecordUserGroup.getUserRecordID()) });
          }
        }
      } else if (MtmWorkflowStepUserActor.ACTOR_TYPE_ROLE.equals(mtmUserActor.getActorType())) {
        // Find User IDs By Role ID.
        List roleAry = new ArrayList();
        roleAry.add(mtmUserActor.getActorID());
        ArrayList tmpAry = (ArrayList)mtmUserRecordUserRoleDAO.getListByUserRoleAry(roleAry);
        for (int j = 0; j < tmpAry.size(); j++) {
          MtmUserRecordUserRole tmpUserRecordUserRole = (MtmUserRecordUserRole)tmpAry.get(j);
          if (recipientHash.get(tmpUserRecordUserRole.getUserRecordID()) == null) {
            recipientHash.put(tmpUserRecordUserRole.getUserRecordID(), new String[]{ UserInfoFactory.getUserFullName(tmpUserRecordUserRole.getUserRecordID()), UserInfoFactory.getUserEmailAddress(tmpUserRecordUserRole.getUserRecordID()) });
          }
        }
        
        ArrayList tmpGroupAry = (ArrayList)mtmUserGroupUserRoleDAO.getListByUserRoleAry(roleAry);
        for (int j = 0; j < tmpGroupAry.size(); j++) {
          MtmUserGroupUserRole tmpUserGroupUserRole = (MtmUserGroupUserRole)tmpGroupAry.get(j);
          
          List groupAry = new ArrayList();
          groupAry.add(tmpUserGroupUserRole.getUserGroupID());
          ArrayList tmpUserAry = (ArrayList)mtmUserRecordUserGroupDAO.getListByUserGroupAry(groupAry);
          for (int k = 0; k < tmpUserAry.size(); k++) {
            MtmUserRecordUserGroup tmpUserRecordUserGroup = (MtmUserRecordUserGroup)tmpUserAry.get(k);
            if (recipientHash.get(tmpUserRecordUserGroup.getUserRecordID()) == null) {
              recipientHash.put(tmpUserRecordUserGroup.getUserRecordID(), new String[]{ UserInfoFactory.getUserFullName(tmpUserRecordUserGroup.getUserRecordID()), UserInfoFactory.getUserEmailAddress(tmpUserRecordUserGroup.getUserRecordID()) });
            }
          }
        }
      } else if (MtmWorkflowStepUserActor.ACTOR_TYPE_SUBMITTER.equals(mtmUserActor.getActorType())) {
        Integer trackSubmitter = progressDAO.getUserIDForWorkflowTrackSubmitter(wprogress.getTrackID());
        if (trackSubmitter!=null) {
          recipientHash.put(trackSubmitter, new String[]{UserInfoFactory.getUserFullName(trackSubmitter), UserInfoFactory.getUserEmailAddress(trackSubmitter)});
        }
      } else if (MtmWorkflowStepUserActor.ACTOR_TYPE_REPORT_TO.equals(mtmUserActor.getActorType())) {
        Integer trackSubmitter = progressDAO.getUserIDForWorkflowTrackSubmitter(wprogress.getTrackID());
        UserRecord reportTo = (UserRecord) userDAO.getReportToUserByID(trackSubmitter);
        if (reportTo!=null) {
          recipientHash.put(reportTo.getID(), new String[]{UserInfoFactory.getUserFullName(reportTo.getID()), UserInfoFactory.getUserEmailAddress(reportTo.getID()) });
        }
     /* } else if (MtmWorkflowStepUserActor.ACTOR_TYPE_RUNTIME_ASSIGN.equals(mtmUserActor.getActorType())) {
        List userList = progressDAO.getListUserIDForDynamicAssignProgress(wprogress.getID());
        for (int j=0; j<userList.size(); j++) {
          Integer userID = (Integer) userList.get(j);
          recipientHash.put(userID, new String[]{UserInfoFactory.getUserFullName(userID), UserInfoFactory.getUserEmailAddress(userID)} );
        }//Added by Dick
*/      } else if (MtmWorkflowStepUserActor.ACTOR_TYPE_ACTION_TAKER.equals(mtmUserActor.getActorType())) {
        Integer stepID=mtmUserActor.getActorID();    
        List userRecordList = progressDAO.getUserIDListForWorkflowStepIDAndWorkflowTrackID(stepID,wprogress.getTrackID());
        if (!Utility.isEmpty(userRecordList)) {
          for (int j = 0; j < userRecordList.size(); j++) {
            Integer userRecordID = (Integer) userRecordList.get(j);
            if (recipientHash.get(userRecordID) == null) {
              recipientHash.put(userRecordID, new String[]{UserInfoFactory.getUserFullName(userRecordID), UserInfoFactory.getUserEmailAddress(userRecordID)});
            }
          }
        }
      } else if (MtmWorkflowStepUserActor.ACTOR_TYPE_REPORT_TO_OF_ACTION_TAKER.equals(mtmUserActor.getActorType())) {
        Integer stepID=mtmUserActor.getActorID();    
        List userRecordList = progressDAO.getUserIDListForWorkflowStepIDAndWorkflowTrackID(stepID,wprogress.getTrackID());
        if (!Utility.isEmpty(userRecordList)) {
          for (int j = 0; j < userRecordList.size(); j++) {
            Integer userRecordID = (Integer) userRecordList.get(j);
            StaffRecord staffRecord  = (StaffRecord)staffDAO.getObjectByUserRecordID(userRecordID);
            UserRecord reportToUserRecord = (UserRecord)userDAO.getObjectByUserTypeUserLinkID(UserRecord.USER_TYPE_STAFF, staffRecord.getReportToStaffRecordID());
            if (recipientHash.get(reportToUserRecord.getID()) == null) {
              recipientHash.put(reportToUserRecord.getID(), new String[]{UserInfoFactory.getUserFullName(reportToUserRecord.getID()), UserInfoFactory.getUserEmailAddress(reportToUserRecord.getID())});
            }
          }
        }
      } else if (MtmWorkflowStepUserActor.ACTOR_TYPE_PREVIOUS_TASK_ACTION_TAKER.equals(mtmUserActor.getActorType())) {  
      	List progressTwoList = wfProgressTwoDAO.getListByChildProgressID(wprogress.getID());
      	for (int j = 0; !Utility.isEmpty(progressTwoList) && j < progressTwoList.size(); j++) {
      	  MtmWfProgressWfProgress progressTwo = (MtmWfProgressWfProgress)progressTwoList.get(j);
      	  List userRecordList = mtmWfProgressUserRecordDAO.getListByWorkflowProgressID(progressTwo.getParentProgressID());
          if (!Utility.isEmpty(userRecordList)) {
            for (int k = 0; k < userRecordList.size(); k++) {
              MtmWorkflowProgressUserRecord mtmUserRecord  = (MtmWorkflowProgressUserRecord)userRecordList.get(k);
              if (recipientHash.get(mtmUserRecord.getUserRecordID()) == null) {
                recipientHash.put(mtmUserRecord.getUserRecordID(), new String[]{UserInfoFactory.getUserFullName(mtmUserRecord.getUserRecordID()), UserInfoFactory.getUserEmailAddress(mtmUserRecord.getUserRecordID())});
              }
            }
          }
      	}
      }else if (MtmWorkflowStepUserActor.ACTOR_TYPE_REPORT_TO_OF_PREVIOUS_TASK_ACTION_TAKER.equals(mtmUserActor.getActorType())) {  
      	List progressTwoList = wfProgressTwoDAO.getListByChildProgressID(wprogress.getID());
      	for (int j = 0; !Utility.isEmpty(progressTwoList) && j < progressTwoList.size(); j++) {
      	  MtmWfProgressWfProgress progressTwo = (MtmWfProgressWfProgress)progressTwoList.get(j);
      	  List userRecordList = mtmWfProgressUserRecordDAO.getListByWorkflowProgressID(progressTwo.getParentProgressID());
          if (!Utility.isEmpty(userRecordList)) {
            for (int k = 0; k < userRecordList.size(); k++) {
              MtmWorkflowProgressUserRecord mtmUserRecord  = (MtmWorkflowProgressUserRecord)userRecordList.get(k);
              StaffRecord staffRecord  = (StaffRecord)staffDAO.getObjectByUserRecordID(mtmUserRecord.getUserRecordID());
              UserRecord reportToUserRecord = (UserRecord)userDAO.getObjectByUserTypeUserLinkID(UserRecord.USER_TYPE_STAFF, staffRecord.getReportToStaffRecordID());
              if (recipientHash.get(reportToUserRecord.getID()) == null) {
                recipientHash.put(reportToUserRecord.getID(), new String[]{UserInfoFactory.getUserFullName(reportToUserRecord.getID()), UserInfoFactory.getUserEmailAddress(reportToUserRecord.getID())});
              }
            }
          }
      	}
      }
    }
 }
    for (Enumeration e = recipientHash.keys(); e.hasMoreElements();) {
      Integer userRecordID = (Integer) e.nextElement();
      if (!Utility.isEmpty(userRecordID)) {
        for (int h = 0; h < resultList.size(); h++) {
          Integer curRecordID = (Integer)resultList.get(h);
          if (userRecordID.equals(curRecordID)) {
            break;
          }
        }
        resultList.add(userRecordID);
      }
    }
    
    return(resultList);
  }
  
  /**
   * Gets a list of all actor email info by workflow progress and rule for given workflow
   * progress and workflow notfiy rule
   *  
   * @param wfProgress The workflow progress
   * @param notfiyRuleID The workflow notfiy rule ID
   * @return list of all actor email info
   * @throws ApplicationException
   */
  public ArrayList getAllActorEmailInfoListByWorkflowProgressAndRuleID(WorkflowProgress wfProgress, Integer notfiyRuleID, boolean isProgressRuleBean) throws ApplicationException {
    Hashtable recipientHash = new Hashtable();
    ArrayList resultList = new ArrayList();
    SessionContainer sessionCon = new SessionContainer();
    WorkflowStepDAObject stepDAO = new WorkflowStepDAObject(sessionCon, conn);
    WorkflowProgressManager progressManager = new WorkflowProgressManager(sessionCon, conn);
    MtmWfStepNotificationTargetDAObject notificationTargetDAO = new MtmWfStepNotificationTargetDAObject(sessionCon, conn);
    MtmWorkflowProgressNotifyTargetDAObject progressNotificationTargetDAO = new MtmWorkflowProgressNotifyTargetDAObject(sessionCon, conn);
    List notificationTargetList = new ArrayList();
    if (isProgressRuleBean) {
      notificationTargetList = progressNotificationTargetDAO.getListByNotifyRuleID(notfiyRuleID);
    } else {
      notificationTargetList = notificationTargetDAO.getListByNotifyRuleID(notfiyRuleID);
    }
    for(int i=0; i<notificationTargetList.size(); i++){
      List actorList = new ArrayList();
      if (isProgressRuleBean) {
        MtmWorkflowProgressNotifyTarget notificationTarget = (MtmWorkflowProgressNotifyTarget)notificationTargetList.get(i);
        if (MtmWorkflowStepUserActor.ACTOR_TYPE_PREVIOUS_TASK_ACTION_TAKER.equals(notificationTarget.getTargetType()) || MtmWorkflowStepUserActor.ACTOR_TYPE_PREVIOUS_TASK_OWNER.equals(notificationTarget.getTargetType()) || MtmWorkflowStepUserActor.ACTOR_TYPE_REPORT_TO_OF_PREVIOUS_TASK_ACTION_TAKER.equals(notificationTarget.getTargetType())) {
          actorList = progressManager.getActorIDListByProgressIDAndRecordID(notificationTarget.getTargetType(), wfProgress.getWorkflowStepID(), wfProgress.getTrackID());    
        } else {
          actorList = progressManager.getActorIDListByProgressIDAndRecordID(notificationTarget.getTargetType(), notificationTarget.getTargetID(), wfProgress.getTrackID());
        } 
      } else {
        MtmWfStepNotificationTarget notificationTarget = (MtmWfStepNotificationTarget)notificationTargetList.get(i);
        if (MtmWorkflowStepUserActor.ACTOR_TYPE_PREVIOUS_TASK_ACTION_TAKER.equals(notificationTarget.getTargetType()) || MtmWorkflowStepUserActor.ACTOR_TYPE_PREVIOUS_TASK_OWNER.equals(notificationTarget.getTargetType()) || MtmWorkflowStepUserActor.ACTOR_TYPE_REPORT_TO_OF_PREVIOUS_TASK_ACTION_TAKER.equals(notificationTarget.getTargetType())) {
          actorList = progressManager.getActorIDListByProgressIDAndRecordID(notificationTarget.getTargetType(), wfProgress.getWorkflowStepID(), wfProgress.getTrackID());    
        } else {
          actorList = progressManager.getActorIDListByProgressIDAndRecordID(notificationTarget.getTargetType(), notificationTarget.getTargetID(), wfProgress.getTrackID());
        } 
      }
      for (int j = 0; j < actorList.size(); j++) {
        Integer userRecordID = (Integer) actorList.get(j);
        if (recipientHash.get(userRecordID) == null) {
          recipientHash.put(userRecordID, new String[]{ UserInfoFactory.getUserFullName(userRecordID), UserInfoFactory.getUserEmailAddress(userRecordID) });
        }
      }
    }
    for (Enumeration e = recipientHash.keys(); e.hasMoreElements();) {
      Integer userRecordID = (Integer) e.nextElement();
      if (!Utility.isEmpty(userRecordID)) {
        for (int h = 0; h < resultList.size(); h++) {
          Integer curRecordID = (Integer)resultList.get(h);
          if (userRecordID.equals(curRecordID)) {
            break;
          }
        }
        resultList.add(userRecordID);
      }
    }  
    return(resultList);
  }
  /**
   * Gets all the recipients id who is the action taker of the given workflow progress
   * 
   * @param wprogress The workflow progress
   * @return List of user record id
   * @throws ApplicationException
   * @see com.dcivision.user.bean.UserRecord
   */
  public ArrayList getAllActionTakerEmailInfoListByStep(WorkflowProgress wprogress) throws ApplicationException {
    SessionContainer sessionCon = new SessionContainer();
    
    Hashtable recipientHash = new Hashtable();
    ArrayList resultList = new ArrayList();
    MtmWorkflowProgressUserRecordDAObject progressUserRecordDAO = new MtmWorkflowProgressUserRecordDAObject(sessionCon, conn);
    List userRecordList = new ArrayList();
    try {
      userRecordList = progressUserRecordDAO.getListByWorkflowProgressID(wprogress.getID());
      if (!Utility.isEmpty(userRecordList)) {
        for (int i = 0; i < userRecordList.size(); i++) {
          MtmWorkflowProgressUserRecord mtmWorkflowProgressUserRecord = (MtmWorkflowProgressUserRecord)userRecordList.get(i);
          recipientHash.put(mtmWorkflowProgressUserRecord.getUserRecordID(), new String[]{UserInfoFactory.getUserFullName(mtmWorkflowProgressUserRecord.getUserRecordID()), UserInfoFactory.getUserEmailAddress(mtmWorkflowProgressUserRecord.getUserRecordID())});
        }
        for (Enumeration e = recipientHash.keys(); e.hasMoreElements();) {
          //String[] tmpStrAry = (String[])recipientHash.get(e.nextElement());
          resultList.add(e.nextElement());
        }
      }
    } catch (ApplicationException ex) {
      log.error(ex, ex);
    }
    return (resultList);
  }
  
  private ArrayList getUserEmailInfoByUserRecordID(Integer userRecordID) throws Exception {
    SessionContainer sessionCon = new SessionContainer();
    
    Hashtable recipientHash = new Hashtable();
    ArrayList resultList = new ArrayList();
    
    List userRecordList = new ArrayList();
    try {
      recipientHash.put(userRecordID, new String[]{UserInfoFactory.getUserFullName(userRecordID), UserInfoFactory.getUserEmailAddress(userRecordID)});
      for (Enumeration e = recipientHash.keys(); e.hasMoreElements();) {
        //String[] tmpStrAry = (String[])recipientHash.get(e.nextElement());
        resultList.add(e.nextElement());
      }
    } catch (Exception ex) {
      log.error(ex, ex);
    }
    return (resultList);
  }
  
  /**
   * Send Notification to Delegated Person By Mail
   * 
   * @param wstep The workflow step
   * @param wprogress The workflow progress
   * @param recipientList List of user record id
   * @throws ApplicationException
   * @see com.dcivision.user.bean.UserRecord
   */
  public void sendNotifyDelegatedPersonByMail(WorkflowStep wstep, WorkflowProgress wprogress, List recipientList) throws ApplicationException {
    if (!wprogress.getStatus().equals(WorkflowProgress.STATUS_PENDING)) {
      return;
    }
    AlertManager am = new AlertManager(sessionContainer, conn);
    am.createWorkflowEmailNotification(wprogress.getTrackID(), UpdateAlert.WORKFLOW_TYPE, UpdateAlert.NOTIFY_DELEGATION_USER, recipientList);
  }
  
  /**
   * Send Notification Delegated Person By System
   * 
   * @param wstep The workflow step
   * @param wprogress The workflow progress 
   * @param recipientList List of user record id
   * @throws ApplicationException
   * @see com.dcivision.user.bean.UserRecord
   */
  public void sendNotifyDelegatedPersonBySystem(WorkflowStep wstep, WorkflowProgress wprogress, List recipientList) throws ApplicationException {
    if (!wprogress.getStatus().equals(WorkflowProgress.STATUS_PENDING)) {
      return;
    }
    sendSystemAlert(wstep, wprogress, UpdateAlert.NOTIFY_DELEGATION_USER, recipientList);
  }
}
